package me.yuxiaoyao.jpa.nativesql.mapper;

import org.springframework.objenesis.Objenesis;
import org.springframework.objenesis.ObjenesisStd;

import javax.persistence.Column;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * @author kerryzhang on 2020/12/16
 */


class ReflectUtil {

    /**
     * Spring 反射工具
     *
     * @author kerryzhang on 2020/12/15
     */
    private static final Objenesis objenesis;

    static {
        objenesis = new ObjenesisStd();
    }

    /**
     * 反射创建实例
     *
     * @param clazz
     * @return not null
     * @author kerryzhang on 2020/12/15
     */
    public static Object newInstance(Class<?> clazz) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        return objenesis.getInstantiatorOf(clazz).newInstance();
    }

    /**
     * 在类中通过字段名获取Field实例
     *
     * @param clazz     类
     * @param fieldName 字段名
     * @return
     * @author kerryzhang on 2020/12/15
     */
    public static Field getDeclaredFieldByColumnName(Class<?> clazz, String fieldName) {
        Field field = null;
        while (clazz != Object.class) {
            try {
                field = clazz.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                // ignored 支持 注解
                Field[] declaredFields = clazz.getDeclaredFields();
                for (Field declaredField : declaredFields) {
                    Column annotation = declaredField.getAnnotation(Column.class);
                    if (annotation == null) {
                        continue;
                    }
                    String name = annotation.name();
                    if (!fieldName.equalsIgnoreCase(name)) {
                        continue;
                    }
                    field = declaredField;
                    break;
                }
            }
            if (field != null) {
                break;
            }
            clazz = clazz.getSuperclass();
        }
        return field;
    }


    /**
     * 获取所有public方法
     *
     * @param cls
     * @return
     */
    public static List<Method> getPublicMethods(Class<?> cls) {
        List<Method> methods = new ArrayList<>();
        while (cls != Object.class) {
            Method[] declaredMethods = cls.getDeclaredMethods();
            methods.addAll(Arrays.asList(declaredMethods));
            cls = cls.getSuperclass();
        }

        return methods;
    }

    /**
     * 获取字段的 set 方法
     *
     * @param fieldName
     * @return name -> setName
     */
    public static String getSetMethodName(String fieldName) {
        String[] s = fieldName.trim().split("_");
        if (s.length > 1) {
            String m = Stream.of(s).reduce((a, b) -> firstToUp(a) + firstToUp(b)).get();
            return "set".concat(m);
        }
        return "set".concat(firstToUp(s[0]));
    }

    private static String firstToUp(String s) {
        if (s.length() > 1) {
            return s.substring(0, 1).toUpperCase().concat(s.substring(1));
        }
        return s.toUpperCase();
    }

    public static Object getClassDefaultValue(Class<?> fieldClassType) {
        if (fieldClassType.isPrimitive()) {
            if (fieldClassType == int.class || fieldClassType == byte.class || fieldClassType == short.class) {
                return 0;
            } else if (fieldClassType == long.class) {
                return 0L;
            } else if (fieldClassType == boolean.class) {
                return false;
            } else if (fieldClassType == float.class) {
                return 0.0f;
            } else if (fieldClassType == double.class) {
                return 0.0d;
            } else if (fieldClassType == char.class) {
                return '\0';
            }
        }
        return null;
    }
}
